package com.sc.nft.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.dao.*;
import com.sc.nft.dto.*;
import com.sc.nft.entity.*;
import com.sc.nft.enums.CollectiveSalesStatusEnum;
import com.sc.nft.enums.DigitalMarketTypeEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.mapper.CollectiveSalesConfigMapper;
import com.sc.nft.pool.UserPool;
import io.swagger.annotations.ApiModelProperty;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.sc.nft.service.CollectiveSalesConfigService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 集售配置表服务接口实现
 *
 * @author zxy
 * @since 2024-09-16 17:11:23
 * @description 由 Mybatisplus Code Generator 创建
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CollectiveSalesConfigServiceImpl implements CollectiveSalesConfigService {
    private final CollectiveSalesConfigDao collectiveSalesConfigDao;
    private final CollectiveSalesConfigMapper collectiveSalesConfigMapper;
    private final DigitalCollectionDao digitalCollectionDao;
    private final CollectiveSalesTimePointsDao collectiveSalesTimePointsDao;
    private final CatenaInfoDao catenaInfoDao;
    private final UserCreatorInfoDao userCreatorInfoDao;
    private final ExitConsensusUserDao exitConsensusUserDao;
    private final UserCollectionConsensusDao userCollectionConsensusDao;
    private final UserCollectionDao userCollectionDao;
    private final CollectiveSalesDao collectiveSalesDao;
    private final UserInfoDao userInfoDao;
    private final FilterIncomeListDao filterIncomeListDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void crateCollectiveSalesConfigs(CollectiveSalesConfigDTO dto) {
        CollectiveSalesConfig collectiveSalesConfig = collectiveSalesConfigDao.getByCollection(dto.getCollectionId());
        Assert.isNull(collectiveSalesConfig,()-> new GlobalRunTimeException("该藏品已经配置过了"));
        verifyCondition(dto);
        List<CollectiveSalesTimePointsConfigDTO> list = dto.getTimePointsConfigs().stream().sorted(Comparator.comparing(CollectiveSalesTimePointsConfigDTO::getTimePoint,Comparator.naturalOrder())).collect(Collectors.toList());
        collectiveSalesConfig = new CollectiveSalesConfig();
        collectiveSalesConfig.setCollectionId(dto.getCollectionId());
        collectiveSalesConfig.setIntoCollectionId(dto.getIntoCollectionId());
        collectiveSalesConfig.setStatus(false);
        collectiveSalesConfig.setEndIntoTime(dto.getEndIntoTime());
        collectiveSalesConfig.setOpenLimit(dto.getOpenLimit());
        collectiveSalesConfig.setRuleImage(dto.getRuleImage());
        collectiveSalesConfig.setServiceFeeRatio(dto.getServiceFeeRatio());
        collectiveSalesConfig.setActivityEndTime(dto.getActivityEndTime());
        collectiveSalesConfig.setStartBuyPrice(list.get(0).getPrice());
        collectiveSalesConfig.setStartBuyTime(list.get(0).getTimePoint());
        collectiveSalesConfig.setSumIntoLimit(dto.getSumIntoLimit());
        collectiveSalesConfig.setStartIntoTime(dto.getStartIntoTime());
        collectiveSalesConfig.setGas(dto.getGas());
        collectiveSalesConfig.setSort(dto.getSort());
        collectiveSalesConfig.insert();
        for (CollectiveSalesTimePointsConfigDTO timePointsConfig : list) {
            Assert.isTrue(NumberUtil.isGreater(timePointsConfig.getPrice().multiply(BigDecimal.ONE.subtract(collectiveSalesConfig.getServiceFeeRatio())),collectiveSalesConfig.getGas()),()-> new GlobalRunTimeException("金额乘(1-服务费比例)必须大于GAS费用"));
            CollectiveSalesTimePoints timePoints = new CollectiveSalesTimePoints();
            timePoints.setCollectiveId(collectiveSalesConfig.getId());
            timePoints.setPrice(timePointsConfig.getPrice());
            timePoints.setTimePoint(timePointsConfig.getTimePoint());
            timePoints.setBuyCollectionId(timePointsConfig.getBuyCollectionId());
            timePoints.insert();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editCollectiveSalesConfigs(CollectiveSalesConfigDTO dto) {
        CollectiveSalesConfig collectiveSalesConfig = collectiveSalesConfigDao.getById(dto.getId());
        Assert.notNull(collectiveSalesConfig,()-> new GlobalRunTimeException("未找到该配置"));
        CollectiveSalesConfig old = collectiveSalesConfigDao.getByCollection(dto.getCollectionId());
        Assert.isTrue(ObjectUtil.isNull(old)||old.getId().longValue()==collectiveSalesConfig.getId().longValue(),()-> new GlobalRunTimeException("该藏品已经配置过了"));
        verifyCondition(dto);
        List<CollectiveSalesTimePointsConfigDTO> list = dto.getTimePointsConfigs().stream().sorted(Comparator.comparing(CollectiveSalesTimePointsConfigDTO::getTimePoint,Comparator.naturalOrder())).collect(Collectors.toList());
        collectiveSalesConfig.setStartBuyPrice(list.get(0).getPrice());
        collectiveSalesConfig.setStartBuyTime(list.get(0).getTimePoint());
        collectiveSalesConfig.setCollectionId(dto.getCollectionId());
        collectiveSalesConfig.setEndIntoTime(dto.getEndIntoTime());
        collectiveSalesConfig.setIntoCollectionId(dto.getIntoCollectionId());
        collectiveSalesConfig.setOpenLimit(dto.getOpenLimit());
        collectiveSalesConfig.setRuleImage(dto.getRuleImage());
        collectiveSalesConfig.setServiceFeeRatio(dto.getServiceFeeRatio());
        collectiveSalesConfig.setActivityEndTime(dto.getActivityEndTime());
        collectiveSalesConfig.setSumIntoLimit(dto.getSumIntoLimit());
        collectiveSalesConfig.setGas(dto.getGas());
        collectiveSalesConfig.setStartIntoTime(dto.getStartIntoTime());
        collectiveSalesConfig.setSort(dto.getSort());
        collectiveSalesConfig.updateById();
        collectiveSalesTimePointsDao.clearByCollectiveId(collectiveSalesConfig.getId());
        for (CollectiveSalesTimePointsConfigDTO timePointsConfig : list) {
            Assert.isTrue(NumberUtil.isGreater(timePointsConfig.getPrice().multiply(BigDecimal.ONE.subtract(collectiveSalesConfig.getServiceFeeRatio())),collectiveSalesConfig.getGas()),()-> new GlobalRunTimeException("金额乘(1-服务费比例)必须大于GAS费用"));
            CollectiveSalesTimePoints timePoints = new CollectiveSalesTimePoints();
            timePoints.setCollectiveId(collectiveSalesConfig.getId());
            timePoints.setPrice(timePointsConfig.getPrice());
            timePoints.setTimePoint(timePointsConfig.getTimePoint());
            timePoints.setBuyCollectionId(timePointsConfig.getBuyCollectionId());
            timePoints.insert();
        }
    }

    @Override
    public Page<CollectiveSalesPageDTO> collectivePage(Page page, Long collectionId, Boolean status) {
        return collectiveSalesConfigMapper.collectivePage(page,collectionId,status);
    }

    @Override
    public Page<CollectiveSalesPageVO> showCustomerPage(Page page) {
        Page<CollectiveSalesPageVO> collectiveSalesPageVOPage = collectiveSalesConfigMapper.showCustomerPage(page);
        for (CollectiveSalesPageVO record : collectiveSalesPageVOPage.getRecords()) {
            switch (record.getActivityStatus()) {
                case WAIT_BUY:
                    record.setLastCount(collectiveSalesDao.getCollectionOnConsignCount(record.getCollectionId()));
                    if(record.getLastCount().intValue()<record.getOpenLimit()){
                        record.setActivityStatus(CollectiveSalesStatusEnum.END);
                    }
                    break;
                case BUY:
                    record.setLastCount(collectiveSalesDao.getCollectionOnConsignCount(record.getCollectionId()));
                    if(record.getLastCount().intValue()==0){
                        record.setActivityStatus(CollectiveSalesStatusEnum.END);
                    }
                 case END:
                    CollectiveSalesTimePoints nowPrice = collectiveSalesTimePointsDao.getNowPrice(record.getId());
                    record.setPrice(nowPrice.getPrice().toPlainString());
                    break;
            }
        }
        return collectiveSalesPageVOPage;
    }

    @Override
    public CollectiveSalesDetailVO getDetail(Long id, UserInfo userInfo) {
        CollectiveSalesConfig collectiveSalesConfig = collectiveSalesConfigDao.getById(id);
        Assert.isTrue(ObjectUtil.isNotNull(collectiveSalesConfig)&&collectiveSalesConfig.getStatus(),()->new GlobalRunTimeException("未找到集售活动"));
        DigitalCollection collection = digitalCollectionDao.getById(collectiveSalesConfig.getCollectionId());
        Assert.notNull(collection,()->new GlobalRunTimeException("未找到藏品"));
        CollectiveSalesDetailVO collectiveSalesDetailVO = new CollectiveSalesDetailVO();
        collectiveSalesDetailVO.setId(id);
        collectiveSalesDetailVO.setCollectionId(collectiveSalesConfig.getCollectionId());
        collectiveSalesDetailVO.setProductPresentation(collection.getProductPresentation());
        collectiveSalesDetailVO.setPrivilegePresentation(collection.getPrivilegePresentation());
        collectiveSalesDetailVO.setFirstTitle(collection.getFirstTitle());
        collectiveSalesDetailVO.setCreationContent(collection.getCreationContent());
        collectiveSalesDetailVO.setProductDetailPicture(collection.getProductDetailPicture());
        collectiveSalesDetailVO.setProductDetailPictureType(collection.getProductDetailPictureType());
        collectiveSalesDetailVO.setCatenaName(catenaInfoDao.getCatenaNameById(collection.getCatenaId()));
        UserCreatorInfo userCreatorInfo = userCreatorInfoDao.getById(collection.getUserCreatorId());
        collectiveSalesDetailVO.setNickName(userInfoDao.getNickNameById(userCreatorInfo.getUserId()));
        collectiveSalesDetailVO.setCreatorAvatarImg(userCreatorInfo.getCreatorAvatarImg());
        collectiveSalesDetailVO.setCollectiveRule(collectiveSalesConfig.getRuleImage());
        collectiveSalesDetailVO.setSumCount(collection.getSumCount());
        collectiveSalesDetailVO.setOpenLimit(collectiveSalesConfig.getOpenLimit());
        collectiveSalesDetailVO.setSumIntoLimit(collectiveSalesConfig.getSumIntoLimit());
        collectiveSalesDetailVO.setLastCount(collectiveSalesDao.getCollectionOnConsignCount(collection.getId()));
        collectiveSalesDetailVO.setDealCount(collectiveSalesDao.getCollectionDealCount(collection.getId()));
        LocalTime nowTime = LocalTime.now();
        DateTime now = DateTime.of(nowTime.toString().substring(0,8),"HH:mm:ss");
        DateTime beginIntoTime = DateTime.of(collectiveSalesConfig.getStartIntoTime());
        DateTime endIntoTime =  DateTime.of(collectiveSalesConfig.getEndIntoTime());;
        DateTime startBuyTime =  DateTime.of(collectiveSalesConfig.getStartBuyTime());;
        DateTime activityEndTime =  DateTime.of(collectiveSalesConfig.getActivityEndTime());
        CollectiveSalesStatusEnum activityStatus = null;
        FilterIncomeList filterIncomeList = filterIncomeListDao.getIsTeamIncomeByUserId(UserPool.getUser().getId());

        Long countDownTime = null;
        if(beginIntoTime.isAfter(now)){
            activityStatus = CollectiveSalesStatusEnum.WAIT_START;
            countDownTime = beginIntoTime.getTime()-now.getTime();
        }else if (beginIntoTime.isBeforeOrEquals(now)&&endIntoTime.isAfterOrEquals(now)){
            activityStatus = CollectiveSalesStatusEnum.INTO;
        }
        else if (endIntoTime.isBefore(now)&&startBuyTime.isAfter(now)){
            if(collectiveSalesDetailVO.getLastCount()<collectiveSalesConfig.getOpenLimit()){
                activityStatus = CollectiveSalesStatusEnum.NOT_ENOUGH;
            }else{
                activityStatus = CollectiveSalesStatusEnum.WAIT_BUY;
                countDownTime = startBuyTime.getTime()-now.getTime();
            }
        }
        else if (startBuyTime.isBeforeOrEquals(now)&&activityEndTime.isAfterOrEquals(now)){
            if(collectiveSalesDao.getCollectionSumCount(collectiveSalesConfig.getCollectionId())<collectiveSalesConfig.getOpenLimit()){
                activityStatus = CollectiveSalesStatusEnum.NOT_ENOUGH;
            }else {
                activityStatus = CollectiveSalesStatusEnum.BUY;
                Integer collectionOnConsignCount = collectiveSalesDao.getCollectionOnConsignCount(collection.getId());
                if (collectionOnConsignCount == 0) {
                    activityStatus = CollectiveSalesStatusEnum.END;
                }
            }
        }else if (activityEndTime.isBefore(now)){
            if(collectiveSalesDao.getCollectionSumCount(collectiveSalesConfig.getCollectionId())<collectiveSalesConfig.getOpenLimit()){
                activityStatus = CollectiveSalesStatusEnum.NOT_ENOUGH;
            }else{
                activityStatus = CollectiveSalesStatusEnum.END;
            }
        }
        collectiveSalesDetailVO.setActivityStatus(activityStatus);
        collectiveSalesDetailVO.setCountDownTime(countDownTime);
        List<CollectiveSalesStageDTO> salesStageList = Lists.newArrayList();
        CollectiveSalesStageDTO startIntoStage = new CollectiveSalesStageDTO();
        startIntoStage.setTitle("开始投入");
        startIntoStage.setContent(StrUtil.format("开始投入 {} - {}", beginIntoTime.toString("HH:mm:ss"),  endIntoTime.toString("HH:mm:ss")));
        startIntoStage.setInThisStage(now.isBeforeOrEquals(endIntoTime)&&now.isAfterOrEquals(beginIntoTime));
        startIntoStage.setShowTime(StrUtil.format("{}-{}",beginIntoTime.toString("HH:mm:ss"),endIntoTime.toString("HH:mm:ss")));
        if(collectiveSalesConfig.getIntoCollectionId()!=null){
            startIntoStage.setNeedHoldCollection(true);
            DigitalCollection intoNeedHoldCollection = digitalCollectionDao.getById(collectiveSalesConfig.getIntoCollectionId());
            startIntoStage.setCreationContent(intoNeedHoldCollection.getCreationContent());
            startIntoStage.setCollectionName(intoNeedHoldCollection.getFirstTitle());
            if(ObjectUtil.isNotNull(filterIncomeList)&&Lists.newArrayList(6L,7L).contains(filterIncomeList.getDaoId().longValue())){
                startIntoStage.setHoldThisCollection(true);
            }else{
                startIntoStage.setHoldThisCollection(userCollectionDao.getByUserIdAndCollectionIdCount(userInfo.getId(),intoNeedHoldCollection.getId())>0);
            }
        }else{
            startIntoStage.setNeedHoldCollection(false);
        }
        salesStageList.add(startIntoStage);
        CollectiveSalesStageDTO readyBuyStage = new CollectiveSalesStageDTO();
        readyBuyStage.setTitle("准备抢购");
        readyBuyStage.setContent("即将进入购买阶段");
        readyBuyStage.setNeedHoldCollection(false);
        readyBuyStage.setInThisStage(now.isAfter(endIntoTime)&&now.isBefore(startBuyTime));
        salesStageList.add(readyBuyStage);
        List<CollectiveSalesTimePoints> salesTimePoints = collectiveSalesTimePointsDao.findByCollectiveId(collectiveSalesConfig.getId());
        for (int i =0 ;i<salesTimePoints.size();i++) {
            CollectiveSalesTimePoints salesTimePoint = salesTimePoints.get(i);
            CollectiveSalesStageDTO buyStage = new CollectiveSalesStageDTO();
            buyStage.setTitle("可购买");
            buyStage.setContent(StrUtil.format("{} 开始 价格：{}",DateUtil.format(salesTimePoint.getTimePoint(),"HH:mm:ss"),salesTimePoint.getPrice().toPlainString()));
            buyStage.setPrice(salesTimePoint.getPrice().toPlainString());
            if(salesTimePoint.getBuyCollectionId()!=null){
                buyStage.setNeedHoldCollection(true);
                DigitalCollection buyNeedHoldCollection = digitalCollectionDao.getById(salesTimePoint.getBuyCollectionId());
                buyStage.setCollectionName(buyNeedHoldCollection.getFirstTitle());
                buyStage.setCreationContent(buyNeedHoldCollection.getCreationContent());
                if(ObjectUtil.isNotNull(filterIncomeList) ){
                    buyStage.setHoldThisCollection(true);
                }else{
                    buyStage.setHoldThisCollection(userCollectionDao.getByUserIdAndCollectionIdCount(userInfo.getId(),buyNeedHoldCollection.getId())>0);
                }
            }else{
                buyStage.setNeedHoldCollection(false);
            }
            buyStage.setInThisStage(false);
            if(now.isAfterOrEquals(startBuyTime)&&now.isBefore(activityEndTime)){
                if(i<salesTimePoints.size()-1){
                    buyStage.setShowTime(StrUtil.format("{}-{}",DateUtil.format(salesTimePoint.getTimePoint(),"HH:mm:ss"),DateUtil.format(salesTimePoints.get(i+1).getTimePoint(),"HH:mm:ss")));
                    buyStage.setInThisStage(now.isAfterOrEquals(salesTimePoint.getTimePoint())&&now.isBefore(salesTimePoints.get(i+1).getTimePoint()));
                }else{
                    buyStage.setShowTime(StrUtil.format("{}-{}",DateUtil.format(salesTimePoint.getTimePoint(),"HH:mm:ss"),DateUtil.format(collectiveSalesConfig.getActivityEndTime(),"HH:mm:ss")));
                    buyStage.setInThisStage(now.isAfterOrEquals(salesTimePoint.getTimePoint()));
                }
            }else{
                buyStage.setInThisStage(false);
            }
            salesStageList.add(buyStage);
        }
        CollectiveSalesStageDTO endStage = new CollectiveSalesStageDTO();
        endStage.setTitle("已结束");
        endStage.setContent(StrUtil.format("{} 活动结束",DateUtil.format(activityEndTime,"HH:mm:ss")));
        endStage.setNeedHoldCollection(false);
        endStage.setShowTime(DateUtil.format(activityEndTime,"HH:mm:ss"));
        endStage.setInThisStage(now.isAfter(activityEndTime));
        salesStageList.add(endStage);
        collectiveSalesDetailVO.setSalesStageList(salesStageList);
        return collectiveSalesDetailVO;
    }

    @Override
    public CollectiveIntoVO getIntoInfo(Long id, UserInfo userInfo) {
        CollectiveSalesConfig collectiveSalesConfig = collectiveSalesConfigDao.getById(id);
        Assert.isTrue(ObjectUtil.isNotNull(collectiveSalesConfig)&&collectiveSalesConfig.getStatus(),()->new GlobalRunTimeException("未找到集售活动"));
        DigitalCollection collection = digitalCollectionDao.getById(collectiveSalesConfig.getCollectionId());
        Assert.notNull(collection,()->new GlobalRunTimeException("未找到藏品"));
        CollectiveIntoVO collectiveIntoVO = new CollectiveIntoVO();
        collectiveIntoVO.setIsConsensusCollection(false);
        if(collection.getCollectionType()== DigitalMarketTypeEnum.ECOLOGY){
            collectiveIntoVO.setIsConsensusCollection(true);
            ExitConsensusUser exitConsensusUser = exitConsensusUserDao.getByUserId(userInfo.getId());
            if(ObjectUtil.isNotNull(exitConsensusUser)&&exitConsensusUser.getStatus()){
                collectiveIntoVO.setConsensusNum("0.0");
            }else{
                UserCollectionConsensus userCollectionConsensus = userCollectionConsensusDao.getBuyUserIdAndCollectionId(userInfo.getId(), collection.getId());
                collectiveIntoVO.setConsensusNum(ObjectUtil.isNull(userCollectionConsensus)?"0.0":userCollectionConsensus.getConsensusNum().toPlainString());
            }
        }
        collectiveIntoVO.setGas(collectiveSalesConfig.getGas().toPlainString());
        collectiveIntoVO.setServiceFeeRatio(collectiveSalesConfig.getServiceFeeRatio().toPlainString());
        collectiveIntoVO.setHoldCount(userCollectionDao.getCountByCollectionNotConsignId(collection.getId(),userInfo.getId()));
        return collectiveIntoVO;
    }

    private void verifyCondition(CollectiveSalesConfigDTO dto){
        Assert.isTrue(dto.getOpenLimit()<dto.getSumIntoLimit(),()-> new GlobalRunTimeException("开启上限必须小于活动上限"));
        Assert.isTrue(dto.getEndIntoTime().after(dto.getStartIntoTime()),()->new GlobalRunTimeException("投入结束时间必须晚于投入开始时间"));
        Assert.isTrue(dto.getActivityEndTime().after(dto.getEndIntoTime()),()->new GlobalRunTimeException("活动结束时间必须晚于投入截至时间"));
        DigitalCollection collection = digitalCollectionDao.getById(dto.getCollectionId());
        Assert.notNull(collection,()->new GlobalRunTimeException("未找到藏品"));
        for (CollectiveSalesTimePointsConfigDTO timePointsConfig : dto.getTimePointsConfigs()) {
            if (timePointsConfig.getBuyCollectionId() != null) {
                Assert.notNull(digitalCollectionDao.getById(timePointsConfig.getBuyCollectionId()),()->new GlobalRunTimeException("未找到购买条件藏品"));
            }
            Assert.isTrue(timePointsConfig.getTimePoint().before(dto.getActivityEndTime()),()-> new GlobalRunTimeException("时间点必须早于活动结束时间"));
            Assert.isTrue(NumberUtil.isLessOrEqual(timePointsConfig.getPrice(),collection.getIssuePrice()),()->new GlobalRunTimeException("价格不能大于藏品地板价"));
        }
    }
}